/*
 * PatronRepresentacionBase.java
 *
 * Copyright 2011 Universidad Francisco de Paula Santander (UFPS).
 * Todos los Derechos Reservados.
 * Creado el 6/03/2011, 12:16:35 PM
 */

package com.ufps.cuatro.util.base;

import com.ufps.cuatro.controlador.render.UtilRender;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ufps.cuatro.modelo.analizador.ObjetoReflexion;
import com.ufps.cuatro.modelo.representacion.ObjetoTipoDatoReflexion;
import com.ufps.cuatro.modelo.representacion.TipoInclusionComponente;
import com.ufps.cuatro.modelo.representacion.UtilRepresentacion;
import com.ufps.cuatro.modelo.representacion.componente.ComponenteDistribuidorGenerador;
import com.ufps.cuatro.modelo.representacion.componente.ComponenteDistribuidorGeneradorClaseCompleja;
import com.ufps.cuatro.modelo.representacion.componente.ComponenteDistribuidorGeneradorMetodo;
import com.ufps.cuatro.modelo.representacion.componente.ComponenteDistribuidorGeneradorMetodoGetter;
import com.ufps.cuatro.modelo.representacion.componente.ComponenteDistribuidorGeneradorMetodoSetter;
import com.ufps.cuatro.util.TipoCaso;
import com.ufps.cuatro.util.generadores.GeneradorComponentes;

/**
 * <i><b>PatronRepresentacionBase:</b></i>:Esta Clase Almacena la Información General
 * de la Fase de Representación, contiene los valores por defecto para representar
 * Clases, Métodos y otras propiedades generales, ademas contiene las referencias
 * de la representaciones por defecto de los tipos de datos soportados. Es la Encargada de
 * Representar los Tipos de Datos del Modelo Analizado.
 * 
 * @author Carlos A. Torres C. - Dolly E. Guerrero. <https://code.google.com/p/tesis4dor/>
 * @version 1.0 6/03/2011
 * @see ObjectBase
 */
public class PatronRepresentacionBase extends ObjectBase{
    private static final long serialVersionUID = -9102839987662387165L;
    
    private String nombre;
    private String tooltips;
    private int idContenedorClase;
    private int idContenedorMetodo;
    private int idContenedorUnitario;
    private int idContenedorEnum;
    private int idContenedorVinculador;
    private int idContenedorSimple;
    private int idContenedorModeloAsociado;
    private ArrayList<ReferenciaPatronBase> objReferenciasBase;
     
    /** 
     * Constructor por Defecto. 
     * Crea un nuevo objeto PatronRepresentacionBase 
     */
    public PatronRepresentacionBase() {
        super();
    }

    /**
     * Constructor utilizado en la Implementación.
     * @param id @DescripcionParametro
     * @param nombre @DescripcionParametro
     * @param tooltips @DescripcionParametro
     * @param idContenedorClase @DescripcionParametro
     * @param idContenedorMetodo @param idContenedorUnitario 
     * @param idContenedorModeloAsociado 
     * @DescripcionParametro
     */
    public PatronRepresentacionBase(int id, String nombre, String tooltips, int idContenedorClase, int idContenedorMetodo, int idContenedorUnitario, int idContenedorModeloAsociado) {
        super(id);
        this.nombre = nombre;
        this.tooltips = tooltips;
        this.idContenedorClase = idContenedorClase;
        this.idContenedorMetodo = idContenedorMetodo;
        this.idContenedorUnitario = idContenedorUnitario;
        this.idContenedorEnum = idContenedorUnitario;
        this.idContenedorVinculador = idContenedorUnitario;
        this.idContenedorSimple = idContenedorUnitario;
        this.idContenedorModeloAsociado = idContenedorModeloAsociado;
    }     

    /**
     * Devuelve el Nombre Asigando al Patron de Representación.
     * @return Nombre Asigando al Patron de Representación.
     */
    public String getNombre() {
        return nombre;
    }

    /**
     * Establece el Nombre al Patron de Representación.
     * @param nombre Nombre Asigando al Patron de Representación.
     */
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }    

    /**
     * Devuelve el Mensaje de Ayuda Corta asociado al Paquete de Representación.
     * @return Mensaje de Ayuda Corta asociado al Paquete de Representación.
     */
    public String getTooltips() {
        return tooltips;
    }

    /**
     * Establece el Mensaje de Ayuda Corta asociado al Paquete de Representación.
     * @param tooltips Mensaje de Ayuda Corta asociado al Paquete de Representación.
     */
    public void setTooltips(String tooltips) {
        this.tooltips = tooltips;
    }

    /**
     * Devuelve la Referencias de Representación asociadas a los Tipos de Datos Soportados.
     * @return Referencias de Representación asociadas a los Tipos de Datos Soportados.
     */
    public ArrayList<ReferenciaPatronBase> getObjReferenciasBase() {
        return objReferenciasBase;
    }

    /**
     * Establece la Referencias de Representación asociadas a los Tipos de Datos Soportados
     * @param objReferenciasBase Referencias de Representación asociadas a los Tipos de Datos Soportados.
     */
    public void setObjReferenciasBase(ArrayList<ReferenciaPatronBase> objReferenciasBase) {
        this.objReferenciasBase = objReferenciasBase;
    }

    /**
     * Devuelve el Id de Generación del Componente Generador Clase asociado a la 
     * representación del Patron.
     * @return Id de Generación del Componente Generador Clase asociado a la 
     * representación del Patron.
     */
    public int getIdContenedorClase() {
        return idContenedorClase;
    }

    /**
     * Establece el Id de Generación del Componente Generador Clase asociado a la 
     * representación del Patron.
     * @param idContenedorClase Id de Generación del Componente Generador Clase asociado a la 
     * representación del Patron.
     */ 
    public void setIdContenedorClase(int idContenedorClase) {
        this.idContenedorClase = idContenedorClase;
    }

    /**
     * Devuelve el Id de Generación del Componente Generador Método asociado a la 
     * representación del Patron.
     * @return Id de Generación del Componente Generador Método asociado a la 
     * representación del Patron.
     */
    public int getIdContenedorMetodo() {
        return idContenedorMetodo;
    }

    /**
     * Establece el Id de Generación del Componente Generador Método asociado a la 
     * representación del Patron.
     * @param idContenedorMetodo Id de Generación del Componente Generador Método asociado a la 
     * representación del Patron.
     */
    public void setIdContenedorMetodo(int idContenedorMetodo) {
        this.idContenedorMetodo = idContenedorMetodo;
    }

    /**
     * Devuelve el Id de Generación del Componente Generador Unitario asociado a la 
     * representación del Patron.
     * @return Id de Generación del Componente Generador Unitario asociado a la 
     * representación del Patron.
     */
    public int getIdContenedorUnitario() {
        return idContenedorUnitario;
    }

    /**
     * Establece el Id de Generación del Componente Generador Unitario asociado a la 
     * representación del Patron.
     * @param idContenedorUnitario Id de Generación del Componente Generador Unitario asociado a la 
     * representación del Patron.
     */
    public void setIdContenedorUnitario(int idContenedorUnitario) {
        this.idContenedorUnitario = idContenedorUnitario;
    }

    /**
     * 
     * @return
     */
    public int getIdContenedorModeloAsociado() {
        return idContenedorModeloAsociado;
    }

    /**
     * 
     * @param idContenedorModeloAsociado
     */
    public void setIdContenedorModeloAsociado(int idContenedorModeloAsociado) {
        this.idContenedorModeloAsociado = idContenedorModeloAsociado;
    }
    
    /**
     * Devuelve el Contenedor Base asociado a la Representación del Componente Generador
     * Clase en el Patron.
     * @return Contenedor Base asociado a la Representación del Componente Generador
     * Clase en el Patron.
     */
    public ComponenteBaseStandar getContenedorBaseClase(){
        return GeneradorComponentes.getContenedorBase(this.idContenedorClase);
    }
    
    /**
     * Devuelve el Componente Generador Clase asociado al Patron.
     * @param objTipoDato 
     * @return Contenedor Base asociado a la Representación del Componente Generador
     * Clase en el Patron.
     */
    public ComponenteDistribuidorGeneradorClaseCompleja getContenedorClaseCompleja(Class objTipoDato){
        return GeneradorComponentes.crearComponenteGeneradorClaseCompleja(
                getContenedorBaseClase(), objTipoDato
                );
    }     
    
    /**
     * Devuelve el Contenedor Base asociado a la Representación del Componente Generador
     * Método en el Patron.
     * @return Contenedor Base asociado a la Representación del Componente Generador
     * Método en el Patron.
     */
    public ComponenteBaseStandar getContenedorBaseMetodo(){
        return GeneradorComponentes.getContenedorBase(this.idContenedorMetodo);
    }
    
    /**
     * 
     * @return
     */
    public ComponenteBaseStandar getContenedorModeloAsociado(){
        return GeneradorComponentes.getContenedorBase(this.idContenedorModeloAsociado);
    }
    
    /**
     * Devuelve el Contenedor Base asociado a la Representación del Componente Generador
     * Método en el Patron.
     * @param objMetodo @DescripcionParametro
     * @return Contenedor Base asociado a la Representación del Componente Generador
     * Método en el Patron.
     */
    public ComponenteDistribuidorGeneradorMetodo getContenedorMetodo(Method objMetodo){
        return GeneradorComponentes.crearComponenteGeneradorMetodo(
                getContenedorBaseMetodo(), objMetodo
                );
    }
    
    /**
     * Devuelve el Contenedor Base asociado a la Representación del Componente Generador
     * Unitario en el Patron.
     * @return Contenedor Base asociado a la Representación del Componente Generador
     * Unitario en el Patron.
     */
    public ComponenteBaseStandar getContenedorBaseUnitario(){
        return GeneradorComponentes.getContenedorBase(this.idContenedorUnitario);
    }
    
    /**
     * Devuelve la Representación para un Tipo de Dato Clase.
     * @param objTipoDato 
     * @param objColeccion Colección de Propiedades y Métodos que se Representarán.
     * @return ComponenteDistribuidorGeneradorClaseCompleja.
     */
    public ComponenteDistribuidorGeneradorClaseCompleja getRepresentacionClase(Class objTipoDato, ArrayList<ObjetoReflexion> objColeccion){
      if(objTipoDato != null){
            ComponenteDistribuidorGeneradorClaseCompleja objComponenteGeneradorClase = this.getContenedorClaseCompleja(objTipoDato);
            for(ObjetoReflexion objReflexion : objColeccion){        
                ComponenteDistribuidorGenerador objComponenteGenerador = 
                        getRepresentacionComponenteGenerador(objReflexion);
                if(objComponenteGenerador != null){
                    objComponenteGenerador.seteIncluido(TipoInclusionComponente.eEnClase);
                    objComponenteGeneradorClase.addComponente(objComponenteGenerador);
                }                        
            }
            objComponenteGeneradorClase.seteIncluido(TipoInclusionComponente.eSinIncluir);
            return null;
        }
      else{            
            UtilRender.printlnConsole("Objeto Tipo Dato Nulo.", UtilRender.ACTION_NORMAL, false);  
            return null;
        }
    }
    
    /**
     * Devuelve la Colección de Representaciones Asociada a la Colección de <code>ObjetoReflexión</code> Analizados
     * de acuerdo al Modo de Operación. 
     * @param objColeccion Colección de <code>ObjetoReflexión</code> Analizados
     * @return Colección de Representaciones.
     */
    public ArrayList<ComponenteDistribuidorGenerador> getRepresentacionColeccion(ArrayList<ObjetoReflexion> objColeccion){
       try{
            ArrayList<ComponenteDistribuidorGenerador> objColecionComponentesGeneradores = new ArrayList<ComponenteDistribuidorGenerador>();
            for(ObjetoReflexion objReflexion : objColeccion){        
                ComponenteDistribuidorGenerador objComponenteGenerador = 
                        getRepresentacionComponenteGenerador(objReflexion);
                if(objComponenteGenerador != null){
                    objColecionComponentesGeneradores.add(objComponenteGenerador);
                }                        
            }
            return objColecionComponentesGeneradores;        
        }catch(java.lang.NullPointerException ex){}
       return null;
    }
    
    /**
     * Devuelve la Representacion del <code>ObjetoReflexion</code> analizado.
     * @param objReflexion <code>ObjetoReflexion</code> analizado.
     * @return Componente Generador Genérico.
     */
    public ComponenteDistribuidorGenerador getRepresentacionComponenteGenerador(ObjetoReflexion objReflexion){
       try{
            //se analiza el objeto reflexion de acuerdo al tipo de Elemento del Modelo analizado        
            if(objReflexion.getObj() instanceof Field){            
                return getRepresentacionAtributo(objReflexion);
            }
            else if(objReflexion.getObj() instanceof Method){
                return getRepresentacionMethod(objReflexion);
            }
            else if(objReflexion.getObj() instanceof Class<?>){
                Class<?> objClass = (Class<?>) objReflexion.getObj();
                ObjetoTipoDatoReflexion objTipoDato = GeneradorComponentes.devolverTipoDatoReflexionPorClass(objClass);
                if(objTipoDato.getObjCaso().geteCaso() == TipoCaso.eClaseMundo){                
                    return null;
                }            
            }
            return null;        
        }catch(java.lang.NullPointerException ex){}
       return null;
    }
    
    /**
     * Devuelve la Representación para un Atributo de una Clase Analizada.
     * @param objReflexion <code>ObjetoReflexion</code> analizado.
     * @return Componente Generador Genérico.
     */
    public ComponenteDistribuidorGenerador getRepresentacionAtributo(ObjetoReflexion objReflexion){
       if(objReflexion != null){
            try{
                Field objField = (Field) objReflexion.getObj();
                Class<?> objClass = objField.getType(); 
                ComponenteDistribuidorGenerador objComponenteGenerador = getRepresentacionClass(objClass);
                objComponenteGenerador.seteIncluido(TipoInclusionComponente.eEnClase);
                return objComponenteGenerador;
            }catch(java.lang.NullPointerException ex){}
            return null;
      }else{            
            UtilRender.printlnConsole("Objeto Reflexión Nulo.", UtilRender.ACTION_NORMAL, false); 
            return null;
        }
    }
    
    /**
     * Devuelve la Representación para un <code>ObjetoTipoDatoReflexion</code>
     * @param objTipoDatoModeloAnalizado Tipo de Dato del Modelo Analizado.
     * @return Componente Generador Genérico.
     */
    public ComponenteDistribuidorGenerador getRepresentacionTipoDato(ObjetoTipoDatoReflexion objTipoDatoModeloAnalizado){        
     if(objTipoDatoModeloAnalizado != null){
            try{
            ComponenteBase objComponenteBase = GeneradorComponentes.devolverComponenteBasePorTipoDato(objTipoDatoModeloAnalizado);
            if(objTipoDatoModeloAnalizado.getObjCaso().geteCaso() == TipoCaso.eClaseMundo){
                System.out.println(objTipoDatoModeloAnalizado.getStrClassPath());
            }
            return (objComponenteBase == null) ? null : GeneradorComponentes.generarRepresentacionPorComponenteBase(objComponenteBase, objTipoDatoModeloAnalizado, true, true);
        }catch(java.lang.NullPointerException ex){}
           return null;
    }else{            
            UtilRender.printlnConsole("Objeto Reflexión Nulo.", UtilRender.ACTION_NORMAL, false); 
            return null;
        }
    }
    
    private ComponenteDistribuidorGenerador getRepresentacionClass(Class<?> objClass){        
        ObjetoTipoDatoReflexion objTipoDatoModeloAnalizado = GeneradorComponentes.devolverTipoDatoReflexionPorClass(objClass);
        ComponenteDistribuidorGenerador objComponenteGenerador = getRepresentacionTipoDato(objTipoDatoModeloAnalizado);        
        objComponenteGenerador.seteIncluido(TipoInclusionComponente.eSinIncluir);
        return objComponenteGenerador;
    }       
    
    /**
     * Devuelve la Representación para un Método de una Clase Analizada.
     * @param objReflexion <code>ObjetoReflexion</code> analizado.     
     * @return Componente Generador Método.
     */
    public ComponenteDistribuidorGeneradorMetodo getRepresentacionMethod(ObjetoReflexion objReflexion){
       if( objReflexion != null){
            try{
                if(objReflexion.getObj() instanceof Method){            
                    Method objMethod = (Method) objReflexion.getObj();
                    if(UtilRepresentacion.isGetter(objMethod) || UtilRepresentacion.isIs(objMethod)){
                        ComponenteDistribuidorGeneradorMetodo objComponenteGeneradorMetodo = getContenedorMetodo(objMethod);
                        ComponenteDistribuidorGenerador objComponenteGenerador = getRepresentacionClass(objMethod.getReturnType());
                        ComponenteDistribuidorGeneradorMetodoGetter objComponenteGeneradorMetodoGetter = (ComponenteDistribuidorGeneradorMetodoGetter) objComponenteGeneradorMetodo;
                        objComponenteGeneradorMetodoGetter.setObjComponenteGeneradorReturn(objComponenteGenerador);
                        return objComponenteGeneradorMetodoGetter;
                    }
                    else if(UtilRepresentacion.isSetter(objMethod)){
                        ComponenteDistribuidorGeneradorMetodo objComponenteGeneradorMetodo = getContenedorMetodo(objMethod);
                        ComponenteDistribuidorGenerador objComponenteGenerador = getRepresentacionClass(objMethod.getReturnType());
                        ComponenteDistribuidorGeneradorMetodoSetter objComponenteGeneradorMetodoSetter = (ComponenteDistribuidorGeneradorMetodoSetter) objComponenteGeneradorMetodo;
                        objComponenteGeneradorMetodoSetter.setObjComponenteGeneradorParam(objComponenteGenerador);
                        return objComponenteGeneradorMetodoSetter;
                    }
                    else{
                        return getContenedorMetodo(objMethod);
                    }
                }
            } catch (java.lang.NullPointerException ex) {
                Logger.getLogger(PatronRepresentacionBase.class.getName()).log(Level.SEVERE, null, ex);
            } catch (java.lang.ClassCastException ex) {
                Logger.getLogger(PatronRepresentacionBase.class.getName()).log(Level.SEVERE, null, ex);
            }
            return null;
       }
       else{            
            UtilRender.printlnConsole("Objeto Reflexión Nulo.", UtilRender.ACTION_NORMAL, false);
            return null;
        }
    }
    
    
    /**
     * Devuelve la referencia (si existe) que Representará al Tipo de Dato en el Patron Actual. 
     * @param objTipoDatoRepresentacionBase Tipo de Dato en el Patron Actual. 
     * @return Referencia de Representación.
     */
    public ReferenciaPatronBase getReferenciaBaseTipoDato(TipoDatoRepresentacionBase objTipoDatoRepresentacionBase){
       try{
        for(ReferenciaPatronBase objRefBase : this.objReferenciasBase){
            if(objRefBase.getTipoDato().equals(objTipoDatoRepresentacionBase)){
                return objRefBase;            
            }
        }
        }catch(java.lang.NullPointerException ex){}
        return null;
    }
    
    @Override
    public int compareTo(Object o) {
      try{
            PatronRepresentacionBase obj = (PatronRepresentacionBase) o;
            if(this.id > obj.id) {
                return 1;
            }
            else if(this.id < obj.id) {
                return -1;
            }
            else {
                return 0;
            }
        }catch(java.lang.NullPointerException ex){}
      return 0;
    }   

    @Override
    public String toString() {
       try{
            return nombre;
        }catch(java.lang.NullPointerException ex){}
       return "";
    }
}

